package com.ruogu.algorithmic.chapter01;

import java.util.Arrays;

/**
 * 开始有100个人，每个人都有100元在每一轮都做如下的事情:
 * 每个人都必须拿出1元钱给除自己以外的其他人，给谁完全随机。
 * 如果某个人在这一轮的钱数为0，那么他可以不给。
 * 接收发生很多很多轮之后，这100人的社会财富分布很均匀吗?
 */
public class C001_Experiment {

    public static void main(String[] args) {
        System.out.println("一个社会的基尼系数是一个在0~1之间的小数");
        System.out.println("基尼系数为0代表所有人的财富完全一样");
        System.out.println("基尼系数为1代表有1个人掌握了全社会的财富");
        System.out.println("基尼系数越小，代表社会财富分布越均衡;越大则代表财富分布越不均衡");
        System.out.println("在2022年，世界各国的平均基尼系数为0.44");
        System.out.println("目前普遍认为，当基尼系数到达0.5时");
        System.out.println("就意味着社会贫富差距非常大，分布非常不均匀");
        System.out.println("社会可能会因此陷入危机，比如大量的犯罪或者经历社会动荡");
        System.out.println("测试开始");
        // 测试人数
        int n = 100;
        // 测试的轮数
        int m = 1000000;
        experiment(n, m);
        System.out.println("测试结束");


    }

    public static void experiment(int n, int m) {
        double[] wealth = new double[n];
        Arrays.fill(wealth, 100);
        boolean[] hasMoney = new boolean[n];
        // 循环测试轮数
        for (int i = 0; i < m; i++) {
            Arrays.fill(hasMoney, false);
            for (int j = 0; j < n; j++) {
                hasMoney[j] = wealth[j] > 0;
            }
            for (int j = 0; j < n; j++) {
                if (hasMoney[j]) {
                    // 随机选择一个,默认先设置自己
                    int other = j;
                    while (other == j) {
                        other = (int) (Math.random() * n);
                    }
                    wealth[j]--;
                    wealth[other]++;
                }
            }
        }
        Arrays.sort(wealth);
        System.out.println("列出每个人的财富(从贫穷到富有):");
        for (int i = 0; i < n; i++) {
            System.out.print((int)wealth[i] + " ");
            if (i % 10 == 9) {
                System.out.println();
            }
        }
        System.out.println();
        System.out.println("社会财富的基尼系数为:" + giniCoefficient(wealth));
    }

    private static double giniCoefficient(double[] wealth) {
        // 排序：将所有收入按从小到大排序。
        //计算绝对差之和：求出所有收入对

        // 绝对差之和
        double sumOfAbsoluteDifferences = 0;
        // 总和
        double sumOfWealth = 0;
        for (double value : wealth) {
            sumOfWealth += value;
            for (double v : wealth) {
                sumOfAbsoluteDifferences += Math.abs(value - v);
            }
        }
        return sumOfAbsoluteDifferences / (2 * sumOfWealth * wealth.length);
    }


}
